#include "MainInclude.h"
#include "SnakerFruit.h"
#include "SnakerMap.h"
#include "SnakerPlayer.h"
#include "SnakerUtils.h"

#ifdef _WIN32
#include <windows.h>
#endif

using namespace std;
// #define TST

const int FPS = 20;
const clock_t TPF = (clock_t)(1000 / FPS);

WINDOW* create_newwin(int height, int width, int starty, int startx) {
    WINDOW* local_win = NULL;
    local_win = newwin(height, width, starty, startx);
    box(local_win, '*', '*');
    wrefresh(local_win);
    return local_win;
}

bool ShouldCurscrExit;

int main(int argc, char** argv) {
    srand(SnakerSeed);

    SnakerMap map;
    SnakerCamera* _cam = new SnakerCamera(24, 48);
    SnakerCamera cam = *_cam;
    map.Init();

    // vector<SnakerPlayer*> players;
    // int playern = 0;
    // if (!argc) playern = 1;
    // for (int i = 0; i < playern; i++) {
    //     players.push_back(new SnakerPlayer(map.FindChunk(0, 0), &map));
    // }

    int playern = 1;
    SnakerPlayer* players[1];
    players[0] = new SnakerPlayer(map.FindChunk(0, 0), &map);
    // map.FindChunk(0, 0);

    // players[0]->Update(1);
    // cout << players[0]->posList.size() << endl;
    // cam.Move(players[0]->posList.front());

    // cout << GetDirect(2, 3, 5, 3) << endl;

    cout << "Initiation complete." << endl;
    system("PAUSE");

    // WINDOW* my_win = initscr();
    // int startx = 0, starty = 0, width = 96, height = 72;
    // int ch = 0;
    // wresize(stdscr, 96, 72);
    initscr();
    raw();
    noecho();
    halfdelay(1);
    curs_set(0);
    keypad(stdscr, true);
    // box(stdscr, '*', '*');
    start_color();
    int width = 120, height = 40;
#ifdef _WIN32
    resize_term(height, width);
    resize_window(stdscr, height, width);
#endif
    refresh();

    // my_win = create_newwin(height, width, starty, startx);

    ShouldCurscrExit = false;
    TimeCounter frameTimeCounter;

    // char* c = "Hello world!";
    frameTimeCounter.Start();
    string s;
    int key, cmd = STEP_UP;

    while (!ShouldCurscrExit) {
#ifndef TST

        mvprintw(0, 0, ("FPS: " + to_string(FPS) + "     ").data());
        mvprintw(1, 0, ("Frames passed: " + to_string(frameTimeCounter.Read() / TPF) + "     ").data());
        mvprintw(2, 0, ("KEY: " + to_string(key) + "     ").data());
        mvprintw(3, 0, "Press arrow keys to move the camera. Press ESC or Q to exit.");
        // mvprintw(7, 0, map.DisplayChunk(map.mapOrigin()).data());

        if (frameTimeCounter.Read() / TPF > 0) {
            frameTimeCounter.Start();

            // int width = 120, height = 40;
            getmaxyx(stdscr, height, width);
#ifdef _WIN32
            resize_term(height, width);
            resize_window(stdscr, height, width);
#endif

            // int cmd;
            switch (key) {
                case KEY_LEFT:
                    // cam.Move(STEP_LEFT, 1);
                    cmd = STEP_LEFT;
                    // key = 0;
                    break;
                case KEY_UP:
                    // cam.Move(STEP_UP, 1);
                    cmd = STEP_UP;
                    // key = 0;
                    break;
                case KEY_DOWN:
                    // cam.Move(STEP_DOWN, 1);
                    cmd = STEP_DOWN;
                    // key = 0;
                    break;
                case KEY_RIGHT:
                    // cam.Move(STEP_RIGHT, 1);
                    cmd = STEP_RIGHT;
                    // key = 0;
                    break;

                default:
                    break;
            }
            // players[0]->Update(cmd, &cam);
            // cam.Move(players[0]->posList.front());
            for (int i = 0; i < playern; i++) {
                if (!players[i]->isDead) {
                    SnakerPlayer* cur = players[i];
                    cur->Update(cmd, &cam);
                    for (set<SnakerChunk*>::iterator it = cur->chunkSet.begin(); it != cur->chunkSet.end(); it++) {
                        map.GenerateFruit(*it, new SnakerFruit(vector<buff>{BUFF_SCORE_100, BUFF_LEN_1}, "P#2"));
                    }
                }
            }

            string canvas = cam.Render2String(&map);
            mvprintw((height - cam.size[0]) / 2 - 1, (width - cam.size[1]) / 3 - 1, "+");
            mvprintw((height - cam.size[0]) / 2 - 1, (width - cam.size[1]) / 3 + cam.size[1], "+");
            mvprintw((height - cam.size[0]) / 2 + cam.size[0], (width - cam.size[1]) / 3 - 1, "+");
            mvprintw((height - cam.size[0]) / 2 + cam.size[0], (width - cam.size[1]) / 3 + cam.size[1], "+");
            for (int i = 0; i < cam.size[1]; i++) mvprintw((height - cam.size[0]) / 2 - 1, (width - cam.size[1]) / 3 + i, "-");
            for (int i = 0; i < cam.size[1]; i++) mvprintw((height - cam.size[0]) / 2 + cam.size[0], (width - cam.size[1]) / 3 + i, "-");
            for (int i = 0; i < cam.size[0]; i++) mvprintw((height - cam.size[0]) / 2 + i, (width - cam.size[1]) / 3 - 1, ("|" + canvas.substr(i * (cam.size[1] + 1), cam.size[1]) + "|").data());
            init_pair(2, COLOR_WHITE, COLOR_RED);
            for (int i = 0; i < cam.size[0]; i++) {
                string buffer = canvas.substr(i * (cam.size[1] + 1), cam.size[1]);
                mvprintw((height - cam.size[0]) / 2 + i, (width - cam.size[1]) / 3 - 1, ("|" + buffer + "|").data());
                for (int j = 0; j < cam.size[1]; j++) {
                    if (buffer[j] == 'P') {
                        attron(COLOR_PAIR(2));
                        mvaddch((height - cam.size[0]) / 2 + i, (width - cam.size[1]) / 3 + j, 'P');
                        attroff(COLOR_PAIR(2));
                    }
                }
            }
            mvprintw(4, 0, "Amount of chunks generated: %d", map.chunkMap.size());
            mvprintw((height - cam.size[0]) / 2, width / 3 + cam.size[1] * 2 / 3 + 1, "Scoreboard");
            
            for (int j = 0; j < playern; j++) {
                mvprintw((height - cam.size[0]) / 2 + j + 2, width / 3 + cam.size[1] * 2 / 3 + 1, "Snake %d : %d", j, players[j]->score);
                if (players[j]->isDead) continue;
                // players[j]->Update(cmd, &cam);
                for (int i = 0; i < players[j]->paintBoard.size(); i++) {
                    init_pair(1, (short)players[j]->paintBoard[i].first.second, COLOR_BLUE);
                    attron(COLOR_PAIR(1));
                    mvaddch((height - cam.size[0]) / 2 + players[j]->paintBoard[i].second.first, (width - cam.size[1]) / 3 + players[j]->paintBoard[i].second.second, players[j]->paintBoard[i].first.first);
                    attroff(COLOR_PAIR(1));
                }
            }

            key = getch();
            refresh();
        }

#else
        int maxx, maxy;
        getmaxyx(stdscr, maxy, maxx);
        // mvprintw(0, 0, "%d %d", maxy, maxx);
        // box(stdscr, '*', '*');
        refresh();
#endif

        // key = getch();
        if (key == 113 || key == 27) ShouldCurscrExit = true;
    }
    // getch();
    endwin();

    return 0;
}
